import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.Statement;


public class RepOkEnhancer {

	public static CFG enhance(CFG cfg) {
		int counter = 0;
		ArrayList<CFGNode> returns = new ArrayList<CFGNode>();
		for (CFGNode node : cfg.getExit().getParents()) {
			for (Statement s : node.getStatements()) {
				if (s.getNodeType() == ASTNode.RETURN_STATEMENT){
					returns.add(node);
					break;
				}
			}
		}
		for (CFGNode node : returns) {
			counter = moveUpReturn(node,cfg,counter);
		}
		
		System.out.println(counter + " enhancements are made");
		return cfg;
	}

	private static int moveUpReturn(CFGNode node, CFG cfg, int counter) {
		ReturnStatement returnSt = null;
		
		for (Statement s : node.getStatements()) {
			if (s.getNodeType() == ASTNode.RETURN_STATEMENT){
				returnSt = (ReturnStatement) s;
				break;
			}
		}
		
		Expression expr = returnSt.getExpression();
		
		if (expr.getNodeType() == Expression.BOOLEAN_LITERAL){
			System.out.println("TODO: Case where we have return boolan literal");
		}
		else if (expr.getNodeType() == Expression.SIMPLE_NAME){
			String varName = ((SimpleName) expr).getIdentifier();
//			System.out.println("TODO: Case where we have a complicated expression as return");
			
			Queue<CFGNode> toCheck = new LinkedList<CFGNode>();
			toCheck.add(node);
			
			node.setLastVal(node.getLastValue(varName));  //-1:null 0:false 1:true
			
			while(!toCheck.isEmpty()){
				CFGNode current = toCheck.remove();
				if(!current.isDefinition(varName) && !current.checked())
					for (CFGNode parent	: current.getParents())
						toCheck.add(parent);
				current.setLastVal(current.getLastValue(varName));
				if (current.includesVariable(varName)){
//					int tempVal = current.getLastValue(varName);
//					if (tempVal == -1)
					if (current.getLastVal() == -1)
						System.out.println("TODO: Case where have to decide whether the values are similar or not");
//					else if (lastVal == -1){
					else if (node.getLastVal() == -1){
//						node.setLastVal(current.getLastVal());
						current.changeToRet(current.getLastVal(),varName,cfg);
						counter++;
					}
					else if (node.getLastVal() == current.getLastVal()){
						current.changeToRet(node.getLastVal(),varName,cfg);
						counter++;
					}
					else
						System.out.println("TODO: Case last value is not as same as current value");
				}
				current.check();
			}
		}
		return counter;
	}

}
